package com.fasterxml.jackson.core.json.async;

import com.fasterxml.jackson.core.async.ByteBufferFeeder;
import com.fasterxml.jackson.core.async.NonBlockingInputFeeder;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;

/**
 * 添加了<code>public Object getObject() throws IOException</code>方法
 */
public class NonBlockingByteBufferJsonParser extends NonBlockingUtf8JsonParserBase implements ByteBufferFeeder {
    private ByteBuffer _inputBuffer = ByteBuffer.wrap(NO_BYTES);

    public NonBlockingByteBufferJsonParser(IOContext ctxt, int parserFeatures, ByteQuadsCanonicalizer sym) {
        super(ctxt, parserFeatures, sym);
    }

    @Override
    public NonBlockingInputFeeder getNonBlockingInputFeeder() {
        return this;
    }

    @Override
    public void feedInput(final ByteBuffer byteBuffer) throws IOException {
        if (_inputPtr < _inputEnd) {
            _reportError("Still have %d undecoded bytes, should not call 'feedInput'", _inputEnd - _inputPtr);
        }

        final int start = byteBuffer.position();
        final int end = byteBuffer.limit();

        if (end < start) {
            _reportError("Input end (%d) may not be before start (%d)", end, start);
        }

        if (_endOfInput) {
            _reportError("Already closed, can not feed more input");
        }

        _currInputProcessed += _origBufferLen;
        streamReadConstraints().validateDocumentLength(_currInputProcessed);
        _currInputRowStart = start - (_inputEnd - _currInputRowStart);
        _currBufferStart = start;
        _inputBuffer = byteBuffer;
        _inputPtr = start;
        _inputEnd = end;
        _origBufferLen = end - start;
    }

    @Override
    public int releaseBuffered(final OutputStream out) throws IOException {
        final int avail = _inputEnd - _inputPtr;
        if (avail > 0) {
            final WritableByteChannel channel = Channels.newChannel(out);
            channel.write(_inputBuffer);
        }
        return avail;
    }

    @Override
    public Object getObject() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    protected byte getNextSignedByteFromBuffer() {
        return _inputBuffer.get(_inputPtr++);
    }

    @Override
    protected int getNextUnsignedByteFromBuffer() {
        return _inputBuffer.get(_inputPtr++) & 0xFF;
    }

    @Override
    protected byte getByteFromBuffer(final int ptr) {
        return _inputBuffer.get(ptr);
    }
}
